Skip to content

feat(beads): scope fleet snapshot and Bearings reads to firstmate's fleet label - #28

Merged
trillium merged 4 commits into
mainfrom
fm/beads-migration-s1-snapshot-gap
Aug 1, 2026
Merged

feat(beads): scope fleet snapshot and Bearings reads to firstmate's fleet label#28
trillium merged 4 commits into
mainfrom
fm/beads-migration-s1-snapshot-gap

Conversation

@trillium

@trillium trillium commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Intent

Beads-authority migration Stage 0 + Stage 1: define and document a firstmate-fleet beads label (fleet:firstmate) so task list calls can scope to firstmate's own fleet, then make bin/fm-fleet-snapshot.sh and bin/fm-bearings-snapshot.sh read this fleet's in-flight/queued state from the beads store (scoped by that label) when config/backlog-backend=beads. Default (tasks-axi/manual) backend output must stay byte-identical. Read-capability only: no home is flipped to beads, no data migrated, no fm-spawn/fm-teardown/decision-hold changes.

What Changed

  • Defined and documented a fleet:firstmate beads label convention in bin/fm-tasks-axi-lib.sh so task list calls can be scoped to this fleet's own beads.
  • Added a backlog_json_beads path to bin/fm-fleet-snapshot.sh that reads in-flight/queued state from the beads store (via task list --label ... --json) when config/backlog-backend=beads, bounded by a read limit/timeout, with null-safe id/title handling and truncation disclosure; default tasks-axi/manual backend output is unchanged.
  • Wired bin/fm-bearings-snapshot.sh to surface the beads-backed fleet view alongside the existing backends, and updated docs/configuration.md to document the new snapshot shape, environment bounds, and the not-yet-wired fleet label.
  • Added tests/fm-beads-backend.test.sh and tests/fm-fleet-snapshot-view.test.sh coverage for the new beads-scoped snapshot path.

Risk Assessment

✅ Low: The change is read-only (no fm-spawn/fm-teardown/data mutation), gated behind config/backlog-backend=beads which no home currently sets, preserves byte-identical default-backend output (covered by a dedicated regression test), and the three warnings/info items from round 1 (timeout, null-title crash, silent truncation) have already been fixed; only a minor, currently-inert schema inconsistency remains.

Testing

All existing and new automated tests pass (fm-beads-backend.test.sh, fm-fleet-snapshot-view.test.sh, fm-bearings-snapshot.test.sh with no regressions), and manual end-to-end CLI runs confirm the beads-scoped fleet:firstmate label correctly drives fm-fleet-snapshot.sh and fm-bearings-snapshot.sh output while the default tasks-axi/manual backend output remains byte-identical to the base commit.

Evidence: Beads-backend fleet snapshot JSON (real fm-fleet-snapshot.sh run against a fake `task` CLI honoring the fleet:firstmate label contract)
{
  "schema": "fm-fleet-snapshot.v1",
  "generated": "2026-08-01T22:15:10Z",
  "fm_home": "/var/folders/8k/0ll7yqm179v19qqg3qmgcq3m0000gn/T/no-mistakes-evidence/01KYZN665FGQEB9P9V4KW0HQPR/manual-check/home",
  "roots": {
    "fm_root": "/Users/trilliumsmith/.no-mistakes/worktrees/afb8487de4ac/01KYZN665FGQEB9P9V4KW0HQPR",
    "state": "/var/folders/8k/0ll7yqm179v19qqg3qmgcq3m0000gn/T/no-mistakes-evidence/01KYZN665FGQEB9P9V4KW0HQPR/manual-check/home/state",
    "data": "/var/folders/8k/0ll7yqm179v19qqg3qmgcq3m0000gn/T/no-mistakes-evidence/01KYZN665FGQEB9P9V4KW0HQPR/manual-check/home/data",
    "config": "/var/folders/8k/0ll7yqm179v19qqg3qmgcq3m0000gn/T/no-mistakes-evidence/01KYZN665FGQEB9P9V4KW0HQPR/manual-check/home/config",
    "projects": "/var/folders/8k/0ll7yqm179v19qqg3qmgcq3m0000gn/T/no-mistakes-evidence/01KYZN665FGQEB9P9V4KW0HQPR/manual-check/home/projects"
  },
  "backlog": {
    "path": "/var/folders/8k/0ll7yqm179v19qqg3qmgcq3m0000gn/T/no-mistakes-evidence/01KYZN665FGQEB9P9V4KW0HQPR/manual-check/home/data/backlog.md",
    "present": true,
    "source": "beads",
    "fleet_label": "fleet:firstmate",
    "records_truncated": false,
    "records_limit": 200,
    "records": [
      {
        "order": 1,
        "state": "queued",
        "structured": true,
        "id": "fm-a1b2",
        "checked": false,
        "title": "Fix login redirect loop",
        "repo": null,
        "kind": null,
        "priority": "2",
        "hold_reason": null,
        "hold_kind": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": null,
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "fm-a1b2 - Fix login redirect loop",
        "body_lines": [],
        "body_excerpt": "Investigate the auth redirect bug reported in prod.",
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false
      },
      {
        "order": 2,
        "state": "in_flight",
        "structured": true,
        "id": "fm-c3d4",
        "checked": false,
        "title": "Ship dark-mode toggle",
        "repo": null,
        "kind": null,
        "priority": "1",
        "hold_reason": null,
        "hold_kind": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": null,
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "fm-c3d4 - Ship dark-mode toggle",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "worker",
        "requires_child_metadata": false,
        "captain_actionable": false
      },
      {
        "order": 3,
        "state": "queued",
        "structured": true,
        "id": "fm-e5f6",
        "checked": false,
        "title": "Blocked on design review",
        "repo": null,
        "kind": null,
        "priority": "1",
        "hold_reason": null,
        "hold_kind": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": null,
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "fm-e5f6 - Blocked on design review",
        "body_lines": [],
        "body_excerpt": "Waiting on captain sign-off.",
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false
      }
    ]
  },
  "tasks": [],
  "main_inventory": {
    "valid": true,
    "reason": null,
    "orphan_in_flight": [],
    "unstructured_current_count": 0
  },
  "scout_reports": [],
  "secondmate_current": {
    "registry": {
      "present": false,
      "available": true,
      "complete": true,
      "reason": null,
      "provenance": "registered-table",
      "path": "/var/folders/8k/0ll7yqm179v19qqg3qmgcq3m0000gn/T/no-mistakes-evidence/01KYZN665FGQEB9P9V4KW0HQPR/manual-check/home/data/secondmates.md",
      "freshness": {
        "status": "fresh",
        "observed_at": "2026-08-01T22:15:10Z"
      },
      "records": [],
      "input_truncated": false,
      "records_truncated": false,
      "reasons": [],
      "lines_in_window": 0,
      "records_in_window": 0
    },
    "records": [],
    "total_registered": 0,
    "total": 0,
    "shown": 0,
    "truncated": 0
  },
  "secondmate_landed": {
    "records": [],
    "truncated": [],
    "unreadable": [],
    "partial": []
  },
  "secondmate_guidance": {
    "note": "For kind=secondmate, bearings selects validated structured state from that registered home; parent events and bounded terminal evidence are fallback-only supplements and never current-state authority."
  }
}
Evidence: Bearings snapshot rendered from the same beads-backed home (free-rides the snapshot's beads branch)
schema: fm-bearings.v1
home: manual-check/home
generated: "2026-08-01T22:15:18Z"
prs: "not_requested (run: /bearings include PRs)"
in_flight: []
secondmates: []
decisions_open: []
landed: []
gates[2]{id,title,blocked_by,reason,owner}:
  fm-a1b2,Fix login redirect loop,"-","-",(main)
  fm-e5f6,Blocked on design review,"-","-",(main)
reports: []
recorded_prs: []
omitted[7]{surface,reveal}:
  backlog item bodies,"--fields bodies"
  task paths,"--fields paths"
  watch/steer actions,"--fields actions"
  healthy endpoint detail,"--fields endpoints"
  full scout-report inventory,"--all-reports"
  superseded queued items,"--all-queued"
  live PR discovery + checks,"--include-prs"
Evidence: Default-backend byte-identical comparison: base-commit vs target-commit fm-fleet-snapshot.sh JSON output, diffed after stripping only timestamp/root-path fields
Only differing fields between base (4ca2fe9) and target (a155fb5) outputs were `generated`, `fm_root`, and `observed_at` timestamps — all backlog record content, states, and structure were identical, confirming the default (tasks-axi/manual) backend output stayed byte-identical.

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 1 info
  • ⚠️ bin/fm-fleet-snapshot.sh:425 - The new task list --label ... --json call in backlog_json_beads (and the fm_beads_backend_available probe it depends on) runs with no timeout bound, unlike every other external/subprocess read in this file (secondmate summary, registry read, parent activity, terminal check all wrap their command in run_timed with a dedicated FM_SNAPSHOT_*_TIMEOUT). If the beads/task backend hangs (federated store unresponsive, lock contention), fm-fleet-snapshot.sh — used at session start and for supervision decisions — can now hang indefinitely instead of failing fast. Wrap the call in run_timed with a new FM_SNAPSHOT_BEADS_TIMEOUT, consistent with the file's established pattern.
  • ⚠️ bin/fm-fleet-snapshot.sh:467 - raw:(.id + " - " + .title) concatenates .id/.title with no null guard. If any bead returned by task list --json has a null id or title (malformed record from the federated store), jq raises a runtime error, backlog_json_beads returns nonzero, and the top-level BACKLOG_JSON=$(backlog_json) || ... exit 1 aborts the entire snapshot with 'backlog read failed' instead of degrading gracefully the way backlog_json_markdown does for every other missing field (it uses // null throughout). Guard with (.id // "?")/(.title // "(untitled)") or similar.
  • ℹ️ bin/fm-fleet-snapshot.sh:426 - backlog_json_beads caps the beads read at FM_SNAPSHOT_BEADS_LIMIT (200) with no truncation disclosure in the output, whereas every other bounded read in this file (secondmate registry, parent activity, terminal check) surfaces an explicit truncated/records_truncated flag. If a fleet accumulates more than 200 in-flight+queued beads, the snapshot silently drops the overflow with no signal to callers (Bearings, supervisors) that the view is incomplete.

🔧 Fix: Bound beads task list read with timeout, guard null id/title, disclose truncation
1 info still open:

  • ℹ️ bin/fm-fleet-snapshot.sh:463 - backlog_json_beads serializes .priority | tostring for every bead. When a bead has no priority set, jq's .priority is null and tostring turns it into the literal string "null" rather than JSON null, unlike backlog_json_markdown's metadata() helper which yields real null for an absent field. No current consumer reads records[].priority, so there's no live breakage today, but it's a schema inconsistency between the two backend paths that could surprise a future consumer doing priority == null checks (the pattern already used for hold_reason/blocked_reason/local_note in this same file). Fix: priority:(if .priority == null then null else (.priority | tostring) end).
✅ **Test** - passed

✅ No issues found.

  • bash tests/fm-beads-backend.test.sh
  • bash tests/fm-fleet-snapshot-view.test.sh
  • bash tests/fm-bearings-snapshot.test.sh
  • Manual: FM_HOME with config/backlog-backend=beads + fake task CLI matching the real beads list contract, ran bin/fm-fleet-snapshot.sh --json and bin/fm-bearings-snapshot.sh directly
  • Manual: diffed bin/fm-fleet-snapshot.sh --json output between base commit (4ca2fe9, via git archive) and target commit (a155fb5) against an identical markdown-backlog fixture home to confirm byte-identical default-backend output
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

Stage 0 of the beads-authority migration (data/beads-authority-migration-scout/report.md
section 4): define fm_beads_fleet_label() in bin/fm-tasks-axi-lib.sh as the single owner
of the firstmate-fleet label ("fleet:firstmate" by default) that every bead firstmate
creates for its own dispatched work should carry, so a `task list --label` call can scope
to firstmate's fleet instead of the shared federated store's full cross-project set.

Stage 1: bin/fm-fleet-snapshot.sh's backlog_json gains a beads-backed branch
(backlog_json_beads) that reads this fleet's open/in_progress/blocked beads, scoped by
that label, into the same fm-fleet-snapshot.v1 records[] shape the existing markdown
parser (renamed to backlog_json_markdown) produces, when config/backlog-backend=beads.
It falls back to the markdown parse on a beads read failure. Beads-sourced records are
always structured:true with requires_child_metadata:false and captain_actionable:false,
so main_inventory_json never flags them as orphaned or unstructured; dependency-graph
fields and state/*.meta correlation are left for a later stage per the report.

bin/fm-bearings-snapshot.sh needs no functional change: it only ever reads the canonical
snapshot's .backlog.records[] and never re-parses data/backlog.md itself, so it inherits
beads-backend awareness for free. Added a header note documenting that.

Default-backend (tasks-axi/manual) output is unchanged: backlog_json_markdown's body is
untouched, and the beads-only fields (source, fleet_label) only ever appear on the beads
path. A regression test asserts the default path carries neither field.

Documented the label convention and snapshot/Bearings beads-awareness in
docs/configuration.md's "Backlog backend" section.
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@trillium, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 5 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c4a28741-3877-42c0-becc-f4411a37e5f8

📥 Commits

Reviewing files that changed from the base of the PR and between 4ca2fe9 and c5e44a0.

📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • bin/fm-bearings-snapshot.sh
  • bin/fm-fleet-snapshot.sh
  • bin/fm-tasks-axi-lib.sh
  • docs/configuration.md
  • tests/fm-beads-backend.test.sh
  • tests/fm-fleet-snapshot-view.test.sh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@trillium
trillium merged commit 1aefa30 into main Aug 1, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant